/*
GanttProject is an opensource project management tool. License: GPL3
Copyright (C) 2010 Dmitry Barashev

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package net.sourceforge.ganttproject.gui.taskproperties;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.table.AbstractTableModel;

import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.resource.HumanResource;
import net.sourceforge.ganttproject.roles.Role;
import net.sourceforge.ganttproject.task.ResourceAssignment;
import net.sourceforge.ganttproject.task.ResourceAssignmentCollection;
import net.sourceforge.ganttproject.task.ResourceAssignmentMutator;

/**
 * Table model of a table of resources assigned to a task.
 *
 * @author dbarashev (Dmitry Barashev)
 */
class ResourcesTableModel extends AbstractTableModel {

    static enum Column {
        ID("id", String.class),
        NAME("resourcename", String.class),
        UNIT("unit", String.class),
        COORDINATOR("coordinator", Boolean.class),
        ROLE("role", String.class);

        private final String myName;
        private final Class<?> myClass;

        Column(String key, Class<?> clazz) {
            myName = GanttLanguage.getInstance().getText(key);
            myClass = clazz;
        }

        String getName() {
            return myName;
        }

        Class<?> getColumnClass() {
            return myClass;
        }
    }

    private final List<ResourceAssignment> myAssignments;

    private final ResourceAssignmentMutator myMutator;

    private boolean isChanged = false;

    public ResourcesTableModel(ResourceAssignmentCollection assignmentCollection) {
        myAssignments = new ArrayList<ResourceAssignment>(Arrays.asList(assignmentCollection
                .getAssignments()));
        myMutator = assignmentCollection.createMutator();
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return Column.values()[columnIndex].getColumnClass();
    }


    @Override
    public int getColumnCount() {
        return Column.values().length;
    }

    @Override
    public int getRowCount() {
        return myAssignments.size() + 1;
    }

    @Override
    public String getColumnName(int col) {
        return Column.values()[col].getName();
    }

    @Override
    public Object getValueAt(int row, int col) {
        Object result;
        if (row >= 0) {
            if (row < myAssignments.size()) {
                ResourceAssignment assignment = myAssignments.get(row);
                switch (col) {
                case 0:
                    result = String.valueOf(assignment.getResource().getId());
                    break;
                case 1:
                    result = assignment.getResource();
                    break;
                case 2:
                    result = String.valueOf(assignment.getLoad());
                    break;
                case 3:
                    result = new Boolean(assignment.isCoordinator());
                    break;
                case 4:
                    result = assignment.getRoleForAssignment();
                    break;
                default:
                    result = "";
                }
            } else {
                result = null;
            }
        } else {
            throw new IllegalArgumentException("I can't return data in row="
                    + row);
        }
        return result;
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        boolean result = col > 0;
        if (result) {
            result = (col == 2 ? row < myAssignments.size()
                    : row <= myAssignments.size())
                    || col == 3 || col == 4;
        }
        return result;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        if (row >= 0) {
            if (row >= myAssignments.size()) {
                createAssignment(value);
            } else {
                updateAssignment(value, row, col);
            }
        } else {
            throw new IllegalArgumentException("I can't set data in row=" + row);
        }
        isChanged = true;
    }

    private void updateAssignment(Object value, int row, int col) {
        ResourceAssignment updateTarget = myAssignments.get(row);
        switch (col) {
        case 4: {
            updateTarget.setRoleForAssignment((Role) value);
            break;
        }
        case 3: {
            updateTarget.setCoordinator(((Boolean) value).booleanValue());
            break;
        }
        case 2: {
            float loadAsFloat = Float.parseFloat(String.valueOf(value));
            updateTarget.setLoad(loadAsFloat);
            break;
        }
        case 1: {
            if (value == null) {
                updateTarget.delete();
                myAssignments.remove(row);
                fireTableRowsDeleted(row, row);
            } else if (value instanceof HumanResource) {
                float load = updateTarget.getLoad();
                boolean coord = updateTarget.isCoordinator();
                updateTarget.delete();
                myMutator.deleteAssignment(updateTarget.getResource());
                ResourceAssignment newAssignment = myMutator.addAssignment((HumanResource) value);
                newAssignment.setLoad(load);
                newAssignment.setCoordinator(coord);
                myAssignments.set(row, newAssignment);
            }
            break;

        }
        default:
            break;
        }
    }

    private void createAssignment(Object value) {
        if (value instanceof HumanResource) {
            ResourceAssignment newAssignment = myMutator
                    .addAssignment((HumanResource) value);
            newAssignment.setLoad(100);

            boolean coord = false;
            if (myAssignments.isEmpty())
                coord = true;
            newAssignment.setCoordinator(coord);
            newAssignment.setRoleForAssignment(newAssignment.getResource().getRole());
            myAssignments.add(newAssignment);
            fireTableRowsInserted(myAssignments.size(), myAssignments.size());
        }
    }

    public List<ResourceAssignment> getResourcesAssignments() {
        return myAssignments;
    }

    public void commit() {
        myMutator.commit();
    }

    public boolean isChanged() {
        return isChanged;
    }

    public void delete(int[] selectedRows) {
        List<ResourceAssignment> selected = new ArrayList<ResourceAssignment>();
        for (int row : selectedRows) {
            selected.add(myAssignments.get(row));
        }
        for (ResourceAssignment ra : selected) {
            ra.delete();
        }
        myAssignments.removeAll(selected);
        fireTableDataChanged();
    }

}
